#include "Application.h"

namespace vkengine
{
	
	void Application::Run()
	{
		Init();
		InitVulkan();
		MainLoop();
		Cleanup();
		
	}
	void Application::Init()
	{
		m_Window.InitWindow();
		m_Instance = std::make_unique<Instance>();
		m_Device=std::make_unique<Device>();
		m_Pipeline = std::make_unique<Pipeline>();
		m_Texture = std::make_shared<Texture>();
		m_Model = std::make_unique<Model>();
		m_Buffers = std::make_unique<Buffers>();
		m_Renderer = std::make_unique<Renderer>();
		m_Renderer->Init(m_Window.GetWindow());
	}

	
	void Application::InitVulkan()
	{
		m_Instance->CreateInstance();
		m_Instance->SetupDebugMessenger();
		m_Device->CreateSurface(m_Instance->GetInstance(), m_Window.GetWindow());
		m_Device->PickPhysicalDevice(m_Instance->GetInstance());
		m_Device->CreateLogicalDevice();
		m_Device->CreateSwapChain(m_Window.GetWindow());
		m_Device->CreateImageViews(m_Texture.get());
		m_Pipeline->CreateRenderPass(m_Device.get(), m_Device->SwapChainFormat());
		m_Pipeline->CreateDescriptorSetLayout(m_Device->GetDevice());
		m_Pipeline->CreateGraphicsPipeline(m_Device->GetDevice());	
		m_Buffers->CreateCommandPool(m_Device.get());
		m_Device->CreateDepthResources(m_Buffers.get(), m_Texture.get());
		m_Buffers->CreateFramebuffers(m_Device.get(), m_Pipeline.get());
		m_Texture->CreateTextureImage(m_Device.get(), m_Buffers.get());
		m_Texture->CreateTextureImageView(m_Device->GetDevice());
		m_Texture->CreateTextureSampler(m_Device.get());
		m_Model->LoadModel();
		m_Buffers->CreateVertexBuffer(m_Device.get());
		m_Buffers->CreateIndexBuffer(m_Device.get());
		m_Buffers->CreateUniformBuffers(m_Device.get());
		m_Buffers->CreateDescriptorPool(m_Device.get());
		m_Buffers->CreateDescriptorSets(m_Device.get(), m_Pipeline.get(), m_Texture.get());
		m_Buffers->CreateCommandBuffers(m_Device->GetDevice());
		m_Renderer->CreateSyncObjects(m_Device->GetDevice());
	}

	void Application::MainLoop()
	{
		while (!m_Window.ShouldClose())
		{
			glfwPollEvents();
			m_Renderer->DrawFrame(m_Window, m_Device.get(), m_Pipeline.get(), m_Buffers.get(),m_Texture.get());
		}

		m_Renderer->DeviceWaitIdle(m_Device.get());
	}

	void Application::Cleanup()
	{
		m_Device->CleanupSwapChain(m_Buffers.get(), m_Pipeline.get());
		m_Renderer->Cleanup(m_Device.get());
		m_Texture->Cleanup(m_Device->GetDevice());
		m_Buffers->Cleanup(m_Device->GetDevice());
		m_Pipeline->Cleanup(m_Device->GetDevice());
		m_Device->Cleanup(m_Instance->GetInstance());	
		m_Instance->Cleanup();
		m_Window.Cleanup();
	}
	

}